package com.yami.shop.payment;

import com.google.gson.Gson;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
import com.yami.shop.payment.dto.GetJsapiServiceDto;
import com.yami.shop.payment.dto.PayParamDto;
import com.yami.shop.payment.dto.RefundParam;
import com.yami.shop.payment.dto.TransferAccountsDto;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.*;
import java.util.*;

@Service
public class WeChatPayment {
    /** 商户号 */
    public static String wechatpayMchid="16";
    /** 商户证书序列号 */
    public static String wechatpayMchserialno="5D7DB9B1028B6";
    /** 商户私钥 */
    public static String wechatpayPrivatekey="-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDH0aut4gO2wjR1\n" +
            "PbGM84zoZ0b7usufWpf5U+zUJqc4yrBkSQrl3r42yljF45y9t6sAPJUKCQ7pZts3\n" +
            "GX5kKC5i8EwkKtFh380VN+5T2HnKeBGQsfgjxA05qR9eZ3ANvN7A4rLDAhmibU17\n" +
            "hchsJ7+YhwP9faWeREG0mdsMQ8r5XY/GGvwndsgorrYhBqiga/jDVgAli/6Rjb6r\n" +
            "WGm8AzRueAnvtCuiu19pBu/Ygka8rNLYYgmt7md4keVANvOUswGQdfOEpUjFk2t8\n" +
            "Tl5t/w2bsiZmIO3JV-";;
    /** apiV3Key */
    public static String wechatpayApiv3key="f2f4";

    /** 微信支付appid */
    public static String wechatpayAppid="wx3f4";
    /** 微信支付AppSecret */
    public static String wechatpayAppsecret="041f135570";


    public static Map<String, RSAAutoCertificateConfig> config=new HashMap<>();

    /**
     * 获取jsapi服务类
     * @return
     */
    public RSAAutoCertificateConfig getJsapiService(GetJsapiServiceDto dto){
        RSAAutoCertificateConfig rsaAutoCertificateConfig = config.get(dto.getWechatpayAppid());
        if(rsaAutoCertificateConfig == null){
            RSAAutoCertificateConfig build = new RSAAutoCertificateConfig.Builder()
                    .merchantId(dto.getWechatpayMchid())
                    .privateKey(dto.getWechatpayPrivatekey())
                    //.privateKeyFromPath(WxConfig.privateKeyPath)
                    .merchantSerialNumber(dto.getWechatpayMchserialno())
                    .apiV3Key(dto.getWechatpayApiv3key()).build();
            config.put(dto.getWechatpayAppid(),build);
            rsaAutoCertificateConfig = build;
        }
        //JsapiService service = new JsapiService.Builder().config(rsaAutoCertificateConfig).build();
        return rsaAutoCertificateConfig;
    }

    /**
     * 进行支付
     * @param payParam
     * @return
     */
    public String pay(PayParamDto payParam, GetJsapiServiceDto dto) {
        String apiUrl = "https://mall.pengyuevip.com/";

        RSAAutoCertificateConfig jsapiService = getJsapiService(dto);
        JsapiService service = new JsapiService.Builder().config(jsapiService).build();

        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal((int)(Double.parseDouble(payParam.getAmount().toPlainString())*100));
        //amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(payParam.getAppid());
        request.setMchid(payParam.getMerchantId());
        request.setDescription(payParam.getDescription());
        request.setNotifyUrl(apiUrl +"mallApi" + "/wxNotice/payment/notify");//这个回调url必须是https开头的
        //request.setNotifyUrl("http://bwzuf7.natappfree.cc/wxNotice//payment/notify");
        request.setOutTradeNo(payParam.getOutTradeNo());
        Payer payer = new Payer();
        payer.setOpenid(payParam.getOpenid());
        request.setPayer(payer);

        //设置回传参数
        Gson gson=new Gson();
        request.setAttach(gson.toJson(payParam.getParam()));

        PrepayResponse prepay = service.prepay(request);


        String prepayid=prepay.getPrepayId();
        return prepayid;
    }


    /** 商户订单号查询订单 */
    public Transaction queryOrderByOutTradeNo(String orderNum, GetJsapiServiceDto dto) {
        RSAAutoCertificateConfig jsapiService = getJsapiService(dto);
        JsapiService service = new JsapiService.Builder().config(jsapiService).build();
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setOutTradeNo(orderNum);
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        // 调用接口
        return service.queryOrderByOutTradeNo(request);
    }

    /**
     * 支付成功验签
     * @param request
     * @return
     */
    public Map paySuccessCheck(HttpServletRequest request,GetJsapiServiceDto dto) {
        /*Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(dto.getWechatpayMchid())
                        .privateKey(dto.getWechatpayPrivatekey())
                        .merchantSerialNumber(dto.getWechatpayMchserialno())
                        .apiV3Key(dto.getWechatpayApiv3key())
                        .build();*/

        /*RSAAutoCertificateConfig config1 = config.get(dto.getWechatpayAppid());
        if(config1 == null){
            RSAAutoCertificateConfig build = new RSAAutoCertificateConfig.Builder()
                    .merchantId(dto.getWechatpayMchid())
                    .privateKey(dto.getWechatpayPrivatekey())
                    //.privateKeyFromPath(WxConfig.privateKeyPath)
                    .merchantSerialNumber(dto.getWechatpayMchserialno())
                    .apiV3Key(dto.getWechatpayApiv3key()).build();
            config.put(dto.getWechatpayAppid(),build);
            config1 = build;
        }*/

        //获取
        RSAAutoCertificateConfig config1 = getJsapiService(dto);

        // 从请求头中获取信息
        String timestamp                        = request.getHeader("Wechatpay-Timestamp");
        String nonce                            = request.getHeader("Wechatpay-Nonce");
        String signature                        = request.getHeader("Wechatpay-Signature");
        String singType                         = request.getHeader("Wechatpay-Signature-Type");
        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");

        String requestBody = getRequestBody(request);

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPayCertificateSerialNumber)
                .nonce(nonce)
                .signature(signature)
                .signType(singType)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        // 初始化解析器 NotificationParser
        NotificationParser parser = new NotificationParser((NotificationConfig) config1);

        // 这个Transaction是微信包里面的
        Transaction decryptObject = parser.parse(requestParam, Transaction.class);

        TransactionAmount amount = decryptObject.getAmount();
        String outTradeNo = decryptObject.getOutTradeNo();
        String attach = decryptObject.getAttach();

        Map map=new HashMap();
        map.put("amount",amount.getTotal());
        map.put("outTradeNo",outTradeNo);
        map.put("attach",attach);
        return map;
    }
    // 获取请求头里的数据
    private String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try (
                ServletInputStream inputStream = request.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            System.out.println("读取数据流异常:"+e);
        }
        return sb.toString();
    }

    /**
     * 组装支付参数
     * @param prepayId
     * @param prepayId
     * @return
     */
    public Map getPayParameter(String prepayId){
        Map<String,String> map=new HashMap<>();
        map.put("appId",wechatpayAppid);
        map.put("timeStamp",String.valueOf(new Date().getTime()));
        map.put("nonceStr", UUID.randomUUID().toString().replace("-",""));
        map.put("package","prepay_id="+prepayId);
        map.put("signType","RSA");

        String s = map.get("appId") + "\n" + map.get("timeStamp") + "\n" + map.get("nonceStr") + "\n" + map.get("package") + "\n";
        try {
            PrivateKey privateKey1 = PemUtil.loadPrivateKeyFromString(wechatpayPrivatekey);
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey1);
            sign.update(s.getBytes("utf-8"));
            String string = Base64.getEncoder().encodeToString(sign.sign());
            map.put("paySign",string);
            return map;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公众号 code 换取 openid
     * @param code
     * @return
     */
    public String getOpenId(String code) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://api.weixin.qq.com/sns/jscode2session?js_code="+code+"&grant_type=authorization_code&appid="+wechatpayAppid+"&secret="+wechatpayAppsecret)
                .build();

        try {
            Response response = client.newCall(request).execute();
            String string = response.body().string();
            //System.out.println(string);
            Gson gson = new Gson();
            Map map = gson.fromJson(string, Map.class);
            /**
             * {
             * 	"session_key": "G4YmjKXmPsqjDFdtcjp/9A==",
             * 	"openid": "o27Z36yx16I4EF84dpTslNdVhsQY"
             * }
             */
            return (String) map.get("openid");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 申请退款
     * @param refundParam
     */
    public void refundOrder(RefundParam refundParam,GetJsapiServiceDto dto) {
        String apiUrl = "https://mall.pengyuevip.com/";
        BigDecimal bigDecimal = new BigDecimal(100);
        int total = bigDecimal.multiply(new BigDecimal(refundParam.getTotal())).intValue();

        int refund = bigDecimal.multiply(new BigDecimal(refundParam.getRefund())).intValue();

        /*Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(WeChatPayment.wechatpayMchid)
                        .privateKey(WeChatPayment.wechatpayPrivatekey)
                        .merchantSerialNumber(WeChatPayment.wechatpayMchserialno)
                        .apiV3Key(WeChatPayment.wechatpayApiv3key)
                        .build();*/

        RSAAutoCertificateConfig config1 = getJsapiService(dto);

        RefundService service = new RefundService.Builder().config(config1).build();

        //生成随机退款订单号
        //String s = UUID.randomUUID().toString().replace("-","");

        CreateRequest request = new CreateRequest();

        //金额信息
        AmountReq amount = new AmountReq();
        amount.setCurrency("CNY");
        amount.setTotal(Long.valueOf(total));
        amount.setRefund(Long.valueOf(refund));

        request.setAmount(amount);
        request.setOutTradeNo(refundParam.getOutTradeNo());
        request.setOutRefundNo(refundParam.getOutRefundNo());
        //request.setNotifyUrl("http://bwzuf7.natappfree.cc/wxNotice/refund/notify");
        request.setNotifyUrl(apiUrl +"mallApi" + "/wxNotice/refund/notify");

        //发送请求
        Refund refund1 = service.create(request);
    }

    public Map refundSuccessCheck(HttpServletRequest request,GetJsapiServiceDto dto) {
        /*Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(WeChatPayment.wechatpayMchid)
                        .privateKey(WeChatPayment.wechatpayPrivatekey)
                        .merchantSerialNumber(WeChatPayment.wechatpayMchserialno)
                        .apiV3Key(WeChatPayment.wechatpayApiv3key)
                        .build();*/

        RSAAutoCertificateConfig config1 = getJsapiService(dto);

        // 从请求头中获取信息
        String timestamp                        = request.getHeader("Wechatpay-Timestamp");
        String nonce                            = request.getHeader("Wechatpay-Nonce");
        String signature                        = request.getHeader("Wechatpay-Signature");
        String singType                         = request.getHeader("Wechatpay-Signature-Type");
        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");

        String requestBody = getRequestBody(request);

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPayCertificateSerialNumber)
                .nonce(nonce)
                .signature(signature)
                .signType(singType)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        // 初始化解析器 NotificationParser
        NotificationParser parser = new NotificationParser(config1);

        // 这个Transaction是微信包里面的
        RefundNotification decryptObject = parser.parse(requestParam, RefundNotification.class);

        com.wechat.pay.java.service.refund.model.Amount amount = decryptObject.getAmount();
        String outTradeNo = decryptObject.getOutTradeNo();

        System.out.println(amount);

        Map map=new HashMap();
        map.put("amount",amount.getRefund());//本次实际退款金额
        map.put("outTradeNo",outTradeNo);
        map.put("outRefundNo",decryptObject.getOutRefundNo());
        return map;
    }

    /**
     * 商家向用户转账
     * @param transferAccountsDto
     * @param dto
     * @return
     */
    public void transferAccounts(TransferAccountsDto transferAccountsDto, GetJsapiServiceDto dto) {
        RSAAutoCertificateConfig config1 = getJsapiService(dto);

        TransferBatchService build = new TransferBatchService.Builder().config(config1).build();

        InitiateBatchTransferRequest request = new InitiateBatchTransferRequest();
        //https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
        request.setAppid("");


        UUID uuid = UUID.randomUUID();
        request.setOutBatchNo(StringUtils.replace(uuid.toString(),"-",""));
        request.setBatchName("提现");
        request.setBatchRemark("提现");

        String string = transferAccountsDto.getTransferAmount().toPlainString();
        Double v = Double.parseDouble(string) * 100;
        request.setTotalAmount(v.longValue());

        request.setTotalNum(1);

        List<TransferDetailInput> list=new ArrayList<>();

        TransferDetailInput input=new TransferDetailInput();
        UUID uuid1 = UUID.randomUUID();
        input.setOutDetailNo(StringUtils.replace(uuid1.toString(),"-",""));
        input.setTransferAmount(v.longValue());
        input.setTransferRemark("提现");
        input.setOpenid(transferAccountsDto.getOpenid());

        list.add(input);

        request.setTransferDetailList(list);

        InitiateBatchTransferResponse initiateBatchTransferResponse = build.initiateBatchTransfer(request);
    }


    /**
     * 批量提现
     * @param transferAccountsDto
     * @param dto
     */
    public void transferAccountsBatch(List<TransferAccountsDto> transferAccountsDto, GetJsapiServiceDto dto) {
        //总笔数
        int size = transferAccountsDto.size();
        //总金额
        BigDecimal reduce = transferAccountsDto.stream().map(t -> t.getTransferAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
        String string = reduce.toPlainString();
        Double total_amount = (Double.parseDouble(string) * 100);
        long totalAmount = total_amount.longValue();


        RSAAutoCertificateConfig config1 = getJsapiService(dto);

        TransferBatchService build = new TransferBatchService.Builder().config(config1).build();

        InitiateBatchTransferRequest request = new InitiateBatchTransferRequest();
        //https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
        request.setAppid("");


        UUID uuid = UUID.randomUUID();
        request.setOutBatchNo(StringUtils.replace(uuid.toString(),"-",""));
        request.setBatchName("提现");
        request.setBatchRemark("提现");


        request.setTotalAmount(totalAmount);
        request.setTotalNum(size);

        List<TransferDetailInput> list=new ArrayList<>();

        for(TransferAccountsDto dto1:transferAccountsDto){
            String t1 = dto1.getTransferAmount().toPlainString();
            Double t2 = (Double.parseDouble(t1) * 100);
            long t3 = t2.longValue();

            TransferDetailInput input=new TransferDetailInput();
            UUID uuid1 = UUID.randomUUID();
            input.setOutDetailNo(StringUtils.replace(uuid1.toString(),"-",""));
            input.setTransferAmount(t3);
            input.setTransferRemark("提现");
            input.setOpenid(dto1.getOpenid());

            list.add(input);
        }

        request.setTransferDetailList(list);

        InitiateBatchTransferResponse initiateBatchTransferResponse = build.initiateBatchTransfer(request);
    }
}
